using CfgTable;
using IQIGame.Onigao.Framework;
using System;

namespace IQIGame.Onigao.GamePlay
{
    /// <summary>
    /// 条件模块，条件判断入口
    /// </summary>
    public class ConditionModule : Singleton<ConditionModule>
    {
        private ConditionModule() { }

        /// <summary>
        /// 条件检查
        /// </summary>
        /// <param name="player"></param>
        /// <param name="conditionCid"></param>
        /// <param name="curEntity">当前实体，如触发包含条件的服务的实体</param>
        /// <returns>是否成功，失败的条件id</returns>
        public (bool, int) Check(int conditionCid, ConditionBlackboard blackboard)
        {
            if (conditionCid <= 0)
            {
                return (true, 0);
            }
            CfgCondition cfgData = TableCenter.condition.Get(conditionCid);
            ConditionPropFetcherType hostType = (ConditionPropFetcherType)cfgData.Type;

            if (hostType == ConditionPropFetcherType.None) //如果是组合
            {
                if (cfgData.Condition.Count == 0 || cfgData.Condition[0] == 0)
                {
                    LogGame.LogError($"条件检查错误：条件[{cfgData.Id}]既没有配置Type，也没有配置Condition。");
                    return (false, 0);
                }
                //先判断第一个
                (bool lastResult, int lastFailId) = Check(cfgData.Condition[0], blackboard);
                //再与后面的进行逻辑运算
                for (int i = 1; i < cfgData.Condition.Count; i++)
                {
                    int subConditionCid = cfgData.Condition[i];
                    //遇到0则退出，Condition是定长数组，0就意味着已经结束
                    if (subConditionCid == 0)
                    {
                        break;
                    }
                    LogicalOPType logicOP = cfgData.LogicalOP[i - 1];
                    if (logicOP == LogicalOPType.None)
                    {
                        LogGame.LogError($"条件判断错误：不支持逻辑运算符：{logicOP}，Condition.Id：{cfgData.Id}");
                        return (false, subConditionCid);
                    }
                    if (logicOP == LogicalOPType.AND && lastResult == false) //优化，如果逻辑运算符是and，且前一个值是false，直接返回false
                    {
                        continue;
                    }
                    else if (logicOP == LogicalOPType.OR && lastResult == true) //优化，如果逻辑运算符是or，且前一个值是true，直接返回true
                    {
                        lastFailId = 0;
                        continue;
                    }
                    //判断当前条件，并与上一个结果做逻辑运算
                    (bool currentResult, int currentFailedId) = Check(subConditionCid, blackboard);
                    //先确定failId，再为lastResult赋值
                    //如果上一个条件为真，failId以现在的为准，否则仍然以上个为准
                    if (lastResult)
                    {
                        lastFailId = currentFailedId;
                    }
                    //因为上面已排除两种情况（&&false和||true），能走到这里，逻辑运算的结果一定恒等于currentResult，这里直接省去lastResult ||/&& currentResult的运算
                    lastResult = currentResult;
                }
                return (lastResult, lastFailId);
            }
            else //如果不是组合
            {
                bool isOK = CheckInner(blackboard, cfgData);
                int failedId = !isOK ? cfgData.Id : 0;
                return (isOK, failedId);
            }
        }

        private bool CheckInner(ConditionBlackboard blackboard, CfgCondition cfgData)
        {
            ConditionPropFetcherType hostType = (ConditionPropFetcherType)cfgData.Type;
            IConditionPropFetcher host = blackboard.GetHost(hostType, cfgData);
            if (host == null)
            {
                LogGame.LogError($"条件判断错误：根据类型[{hostType}]找不到host。");
                return false;
            }
            bool isOK = false;
            try
            {
                int propValue = host.FetchConditionProp(blackboard, cfgData.SubType, cfgData.CurValueParams);
                LogGame.Log($"条件检查：[大类型 = {cfgData.Type}，子类型 = {cfgData.SubType}，实时属性值 = {propValue}，策划指定的对比值 = {cfgData.SpecifiedValue}，比较运算符 = {cfgData.Comparison}]");
                return CompareValue(propValue, cfgData.SpecifiedValue, cfgData.Comparison);
            }
            catch (Exception e)
            {
                LogGame.LogError($"条件{cfgData.Id}检测失败。\n{e}");
            }
            return isOK;
        }

        /// <summary>
        /// 进行比较运算
        /// </summary>
        /// <param name="currentValue"></param>
        /// <param name="specifiedValue"></param>
        /// <param name="comparison"></param>
        /// <returns></returns>
        private bool CompareValue(int currentValue, int specifiedValue, ComparisonType comparison)
        {
            switch (comparison)
            {
                case ComparisonType.GreaterEqual:
                    return currentValue >= specifiedValue;
                case ComparisonType.LessEqual:
                    return currentValue <= specifiedValue;
                case ComparisonType.NotEqual:
                    return currentValue != specifiedValue;
                case ComparisonType.Equal:
                    return currentValue == specifiedValue;
                case ComparisonType.GreaterThan:
                    return currentValue > specifiedValue;
                case ComparisonType.LessThan:
                    return currentValue < specifiedValue;
                default:
                    LogGame.LogError($"条件判断错误：不支持比较运算符[{comparison}]");
                    return false;
            }
        }
    }
}
